package com.lzb.compressmaster.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;

import com.arthenica.ffmpegkit.FFmpegKit;
import com.arthenica.ffmpegkit.FFmpegSession;
import com.arthenica.ffmpegkit.ReturnCode;
import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.PathUtils;
import com.lzb.compressmaster.Content;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 图片压缩工具类
 * 支持4种压缩类型：智能压缩、高级压缩、指定大小、指定像素
 */
public class ImageCompressor {

    public enum CompressType {
        SMART("智能压缩"),      // 智能压缩
        ADVANCED("高级压缩"),   // 高级压缩
        SIZE("指定大小"),       // 指定大小
        PIXEL("指定像素");       // 指定像素

        private final String name;

        CompressType(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    public enum OutputFormat {
        ORIGINAL("原格式"),   // 原格式
        PNG("PNG"),        // PNG格式
        JPG("JPG"),        // JPG格式
        WEBP("WEBP");        // WebP格式

        private final String name;

        OutputFormat(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    public static class CompressConfig {
        private CompressType compressType;
        private OutputFormat outputFormat = OutputFormat.ORIGINAL;
        private int quality = 2;           // 质量 2-31
        private int width = 1080;              // 目标宽度
        private int height = 1920;             // 目标高度
        private long targetSize = 0;        // 目标文件大小(bytes)
        private float scalePercent = 50f;  // 缩放百分比
        private boolean keepAspectRatio = true; // 保持宽高比
        private String customSuffix = ""; // 自定义后缀

        public CompressConfig(CompressType compressType) {
            this.compressType = compressType;
        }

        public CompressType getCompressType() {
            return compressType;
        }

        public void setCompressType(CompressType compressType) {
            this.compressType = compressType;
        }

        public OutputFormat getOutputFormat() {
            return outputFormat;
        }

        public CompressConfig setOutputFormat(OutputFormat outputFormat) {
            this.outputFormat = outputFormat;
            return this;
        }

        public int getQuality() {
            return quality;
        }

        public CompressConfig setQuality(int quality) {
            this.quality = Math.max(1, Math.min(100, quality));
            return this;
        }

        public int getWidth() {
            return width;
        }

        public CompressConfig setWidth(int width) {
            this.width = Math.max(1, width);
            return this;
        }

        public int getHeight() {
            return height;
        }

        public CompressConfig setHeight(int height) {
            this.height = Math.max(1, height);
            return this;
        }

        public long getTargetSize() {
            return targetSize;
        }

        public CompressConfig setTargetSize(long targetSize) {
            this.targetSize = Math.max(1024, targetSize); // 最小1KB
            return this;
        }

        public float getScalePercent() {
            return scalePercent;
        }

        public CompressConfig setScalePercent(float scalePercent) {
            this.scalePercent = Math.max(1f, Math.min(100f, scalePercent));
            return this;
        }

        public boolean isKeepAspectRatio() {
            return keepAspectRatio;
        }

        public CompressConfig setKeepAspectRatio(boolean keepAspectRatio) {
            this.keepAspectRatio = keepAspectRatio;
            return this;
        }

        public String getCustomSuffix() {
            return customSuffix;
        }

        public CompressConfig setCustomSuffix(String customSuffix) {
            this.customSuffix = customSuffix != null ? customSuffix : "";
            return this;
        }
    }

    public static class CompressResult {
        private String inputPath;
        private String outputPath;
        private boolean success;
        private String errorMessage;
        private long originalSize;
        private long compressedSize;

        public CompressResult(String inputPath, String outputPath, boolean success,
                              String errorMessage, long originalSize, long compressedSize) {
            this.inputPath = inputPath;
            this.outputPath = outputPath;
            this.success = success;
            this.errorMessage = errorMessage;
            this.originalSize = originalSize;
            this.compressedSize = compressedSize;
        }

        public String getInputPath() {
            return inputPath;
        }

        public String getOutputPath() {
            return outputPath;
        }

        public void setOutputPath(String outputPath) {
            this.outputPath = outputPath;
        }

        public boolean isSuccess() {
            return success;
        }

        public String getErrorMessage() {
            return errorMessage;
        }

        public long getOriginalSize() {
            return originalSize;
        }

        public long getCompressedSize() {
            return compressedSize;
        }

        public double getCompressionRatio() {
            return originalSize > 0 ? (1.0 - (double) compressedSize / originalSize) * 100 : 0;
        }
    }

    public interface CompressCallback {
        void onProgress(int current, int total, String fileName);

        void onComplete(List<CompressResult> results);

        void onError(String error);
    }

    /**
     * 批量压缩图片
     */
    public static void compressImages(Context context, List<String> imagePaths,
                                      CompressConfig config, CompressCallback callback) {
        if (imagePaths == null || imagePaths.isEmpty()) {
            callback.onError("没有选择图片");
            return;
        }

        new Thread(() -> {
            List<CompressResult> results = new ArrayList<>();
            android.os.Handler handler = new android.os.Handler(context.getMainLooper());

            for (int i = 0; i < imagePaths.size(); i++) {
                String path = imagePaths.get(i);
                String fileName = FileUtils.getFileName(path);

                // 回调进度
                final int current = i + 1;
                handler.post(() -> callback.onProgress(current, imagePaths.size(), fileName));

                CompressResult result = compressSingleImage(path, config);
                results.add(result);
            }

            handler.post(() -> callback.onComplete(results));
        }).start();
    }

    /**
     * 单张图片压缩
     */
    public static CompressResult compressSingleImage(String imagePath, CompressConfig config) {
        if (!FileUtils.isFileExists(imagePath)) {
            return new CompressResult(imagePath, "", false, "文件不存在", 0, 0);
        }

        File inputFile = new File(imagePath);
        long originalSize = inputFile.length();

        try {
            String outputPath = generateOutputPath(imagePath, config);
            String command = buildFfmpegCommand(imagePath, outputPath, config);

            FFmpegSession session = FFmpegKit.execute(command);

            if (ReturnCode.isSuccess(session.getReturnCode())) {
                File outputFile = new File(outputPath);
                long compressedSize = outputFile.exists() ? outputFile.length() : 0;
                return new CompressResult(imagePath, outputPath, true, "", originalSize, compressedSize);
            } else {
                String error = session.getFailStackTrace();
                return new CompressResult(imagePath, "", false, error, originalSize, 0);
            }
        } catch (Exception e) {
            return new CompressResult(imagePath, "", false, e.getMessage(), originalSize, 0);
        }
    }

    /**
     * 生成输出文件路径
     */
    private static String generateOutputPath(String inputPath, CompressConfig config) {
        String parentDir = PathUtils.getFilesPathExternalFirst() + Content.myPictureCompress;
        File parentFile = new File(parentDir);

        // 确保目录存在
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }

        String fileName = FileUtils.getFileNameNoExtension(inputPath);
        String extension = getOutputExtension(inputPath, config);

        String suffix = config.getCustomSuffix();
//        if (TextUtils.isEmpty(suffix)) {
//            suffix = "_compressed";
//        }

        String outputFileName = fileName + suffix + "." + extension;
        File outputFile = new File(parentFile, outputFileName);

        // 如果文件已存在，添加时间戳
        int counter = 1;
        while (outputFile.exists()) {
            outputFileName = fileName + suffix + "_" + counter + "." + extension;
            outputFile = new File(parentFile, outputFileName);
            counter++;
        }

        return outputFile.getAbsolutePath();
    }

    /**
     * 获取输出文件扩展名
     */
    private static String getOutputExtension(String inputPath, CompressConfig config) {
        if (config.getOutputFormat() == OutputFormat.ORIGINAL) {
            return FileUtils.getFileExtension(inputPath).toLowerCase();
        }

        switch (config.getOutputFormat()) {
            case PNG:
                return "png";
            case JPG:
                return "jpg";
            case WEBP:
                return "webp";
            default:
                return "jpg";
        }
    }

    /**
     * 构建FFmpeg命令
     */
    private static String buildFfmpegCommand(String inputPath, String outputPath, CompressConfig config) {
        StringBuilder command = new StringBuilder();
        command.append("-i \"").append(inputPath).append("\"");

        // 根据压缩类型构建命令
        switch (config.getCompressType()) {
            case SMART:
                command.append(buildSmartCompressCommand(config, inputPath));
                break;
            case ADVANCED:
                command.append(buildAdvancedCompressCommand(config, inputPath));
                break;
            case SIZE:
                command.append(buildSizeCompressCommand(inputPath, config));
                break;
            case PIXEL:
                command.append(buildPixelCompressCommand(config, inputPath));
                break;
        }

        if (config.getCompressType() != CompressType.SIZE) {
            command.append(" -q:v ").append(config.getQuality());
        }

        // 设置输出封装格式
        if (config.getOutputFormat() != OutputFormat.ORIGINAL) {
            switch (config.getOutputFormat()) {
                case PNG:
                    command.append(" -f image2 -c:v png");
                    break;
                case JPG:
                    command.append(" -f image2 -c:v mjpeg");
                    break;
                case WEBP:
                    command.append(" -f image2 -c:v libwebp");
                    break;
            }
        }

        command.append(" \"").append(outputPath).append("\"");
        return command.toString();
    }

    /**
     * 智能压缩命令
     */
    private static String buildSmartCompressCommand(CompressConfig config, String inputPath) {
        // 判断最终格式是否为 PNG
        boolean isPng = config.getOutputFormat() == OutputFormat.PNG ||
                (config.getOutputFormat() == OutputFormat.ORIGINAL &&
                        "png".equalsIgnoreCase(FileUtils.getFileExtension(inputPath)));

        if (isPng) {
            // PNG：先缩放，再调色板量化（128 色）
            return String.format(
                    " -filter_complex \"scale=iw*%f:ih*%f, palettegen=stats_mode=diff[palette];[0:v]scale=iw*%f:ih*%f[pic];[pic][palette]paletteuse=new=1:dither=sierra2_4a\"",
                    0.8, 0.8, 0.8, 0.8);
        } else {
            // 非 PNG：仅缩放
            // 智能压缩：自动调整尺寸和质量
            return " -vf scale=iw*0.8:ih*0.8 -q:v 2";
        }
    }

    /**
     * 高级压缩命令：缩放 + PNG 调色板量化（如果最终是 PNG）
     */
    private static String buildAdvancedCompressCommand(CompressConfig config, String inputPath) {
        float scale = config.getScalePercent() / 100f;

        // 判断最终格式是否为 PNG
        boolean isPng = config.getOutputFormat() == OutputFormat.PNG ||
                (config.getOutputFormat() == OutputFormat.ORIGINAL &&
                        "png".equalsIgnoreCase(FileUtils.getFileExtension(inputPath)));

        if (isPng) {
            // PNG：先缩放，再调色板量化（128 色）
            return String.format(
                    " -filter_complex \"scale=iw*%f:ih*%f, palettegen=stats_mode=diff[palette];[0:v]scale=iw*%f:ih*%f[pic];[pic][palette]paletteuse=new=1:dither=sierra2_4a\"",
                    scale, scale, scale, scale);
        } else {
            // 非 PNG：仅缩放
            return String.format(" -vf scale=iw*%f:ih*%f", scale, scale);
        }
    }

    /**
     * 指定大小压缩命令
     */
    private static String buildSizeCompressCommand(String inputPath, CompressConfig config) {
        long targetSize = config.getTargetSize();
        File inputFile = new File(inputPath);
        long originalSize = inputFile.length();

        if (originalSize <= targetSize) {
            // 如果原文件已经小于目标大小，只进行轻微压缩
            Log.e("TAG", "original: " + originalSize + "target: " + targetSize);
            return " -q:v 2";  // 最高质量
        }

        // 估算压缩比例
        double ratio = (double) targetSize / originalSize;

        // 根据压缩比例计算合适的质量值
        // JPEG: 2-31范围，2最好，31最差
        int quality;
        if (ratio > 0.8) {
            // 轻微压缩
            quality = (int) (2 + (1 - ratio) * 5);  // 2-7
        } else if (ratio > 0.5) {
            // 中等压缩
            quality = (int) (5 + (1 - ratio) * 10);  // 5-15
        } else if (ratio > 0.2) {
            // 较大压缩
            quality = (int) (10 + (1 - ratio) * 15);  // 10-25
        } else {
            // 大幅压缩
            quality = Math.min(31, (int) (20 + (1 - ratio) * 15));  // 20-31
        }

        quality = Math.max(2, Math.min(31, quality));

        Log.e("TAG", "buildSizeCompressCommand: " + String.format(" -q:v %d", quality));
        return String.format(" -q:v %d", quality);
    }

    /**
     * 指定像素压缩命令：缩放 + PNG 调色板量化（如果最终是 PNG）
     */
    private static String buildPixelCompressCommand(CompressConfig config, String inputPath) {
        int width = config.getWidth();
        int height = config.getHeight();

        if (width <= 0 && height <= 0) {
            return "";
        }

        // 判断最终格式是否为 PNG
        boolean isPng = config.getOutputFormat() == OutputFormat.PNG ||
                (config.getOutputFormat() == OutputFormat.ORIGINAL &&
                        "png".equalsIgnoreCase(FileUtils.getFileExtension(inputPath)));

        String scaleExpr;
        if (config.isKeepAspectRatio()) {
            if (width > 0 && height > 0) {
                // 保持宽高比，按最小边缩放
                scaleExpr = String.format(
                        "scale='%d:%d:force_original_aspect_ratio=decrease',pad=%d:%d:(ow-iw)/2:(oh-ih)/2",
                        width, height, width, height);
            } else if (width > 0) {
                scaleExpr = String.format("scale=%d:-1", width);
            } else {
                scaleExpr = String.format("scale=-1:%d", height);
            }
        } else {
            scaleExpr = String.format("scale=%d:%d", width, height);
        }

        if (isPng) {
            // PNG：先缩放，再调色板量化（128 色）
            return String.format(
                    " -filter_complex \"%s, palettegen=stats_mode=diff[palette];[0:v]%s[pic];[pic][palette]paletteuse=new=1:dither=sierra2_4a\"",
                    scaleExpr, scaleExpr);
        } else {
            // 非 PNG：仅缩放
            return " -vf " + scaleExpr;
        }
    }

    /**
     * 获取图片尺寸信息
     */
    public static int[] getImageDimensions(String imagePath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);
        return new int[]{options.outWidth, options.outHeight};
    }

    /**
     * 获取图片文件大小
     */
    public static long getImageFileSize(String imagePath) {
        File file = new File(imagePath);
        return file.exists() ? file.length() : 0;
    }

    /**
     * 批量获取图片信息
     */
    public static List<ImageInfo> getImagesInfo(List<String> imagePaths) {
        List<ImageInfo> infos = new ArrayList<>();
        for (String path : imagePaths) {
            ImageInfo info = getImageInfo(path);
            if (info != null) {
                infos.add(info);
            }
        }
        return infos;
    }

    /**
     * 获取单张图片信息
     */
    public static ImageInfo getImageInfo(String imagePath) {
        if (!FileUtils.isFileExists(imagePath)) {
            return null;
        }

        File file = new File(imagePath);
        int[] dimensions = getImageDimensions(imagePath);

        ImageInfo info = new ImageInfo();
        info.setPath(imagePath);
        info.setFileName(file.getName());
        info.setFileSize(file.length());
        info.setWidth(dimensions[0]);
        info.setHeight(dimensions[1]);
        info.setMimeType(getMimeType(imagePath));

        return info;
    }

    /**
     * 获取MIME类型
     */
    private static String getMimeType(String filePath) {
        String extension = FileUtils.getFileExtension(filePath).toLowerCase();
        switch (extension) {
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "webp":
                return "image/webp";
            case "gif":
                return "image/gif";
            case "bmp":
                return "image/bmp";
            default:
                return "image/*";
        }
    }

    /**
     * 支持的图片格式
     */
    public static boolean isSupportedImage(String filePath) {
        String extension = FileUtils.getFileExtension(filePath).toLowerCase();
        return extension.matches("(?i)(jpg|jpeg|png|webp|gif|bmp)");
    }

    /**
     * 图片信息类
     */
    public static class ImageInfo {
        private String path;
        private String fileName;
        private long fileSize;
        private int width;
        private int height;
        private String mimeType;

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public long getFileSize() {
            return fileSize;
        }

        public void setFileSize(long fileSize) {
            this.fileSize = fileSize;
        }

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        public String getMimeType() {
            return mimeType;
        }

        public void setMimeType(String mimeType) {
            this.mimeType = mimeType;
        }

        public String getFormattedSize() {
            return ConvertUtils.byte2FitMemorySize(fileSize, 2);
        }

        public String getFormattedDimensions() {
            return width + "x" + height;
        }
    }
}